package cn.gene.timeyan.article.webapi.service.impl;

import cn.gene.timeyan.article.service.ArticleService;
import cn.gene.timeyan.article.service.TopService;
import cn.gene.timeyan.article.webapi.mapper.ArticleMapper;
import cn.gene.timeyan.article.webapi.mapper.CommentMapper;
import cn.gene.timeyan.common.constant.RedisConstants;
import cn.gene.timeyan.common.exception.TimeyanServiceException;
import cn.gene.timeyan.common.restful.JsonPage;
import cn.gene.timeyan.common.restful.JsonResult;
import cn.gene.timeyan.common.restful.ResponseCode;
import cn.gene.timeyan.common.utils.FormUtils;
import cn.gene.timeyan.pojo.article.dto.ArticleDTO;
import cn.gene.timeyan.pojo.article.dto.NewArticleDTO;
import cn.gene.timeyan.pojo.article.model.Article;
import cn.gene.timeyan.pojo.article.vo.ArticleVO;
import cn.gene.timeyan.pojo.article.vo.CommentVO;
import cn.gene.timeyan.pojo.article.vo.SimpleArticleVO;
import cn.gene.timeyan.pojo.ums.model.BrowsingHistory;
import cn.gene.timeyan.pojo.ums.vo.UserSimpleVO;
import cn.gene.timeyan.ums.service.IBrowsingHistoryService;
import cn.gene.timeyan.ums.service.IUserDetailService;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 鏂囩珷淇℃伅 服务实现类
 * </p>
 *
 * @author LWG
 * @since 2022-07-25
 */
@Service
@Slf4j
@DubboService
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private TopService topService;
    @DubboReference
    private IUserDetailService dubboUserDetail;
    @DubboReference
    private IBrowsingHistoryService dubboBrowsingHistory;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    @Qualifier("redisTemplate2")
    private RedisTemplate redisTemplate2;
    private static final String COMMENT_TYPE="like";

    @Override
    public JsonPage<Article> getShareByPage(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        log.info("实现分页");
        List<Article> list=articleMapper.findAllList();
        return JsonPage.restPage(new PageInfo<>(list));
    }

    @Override
    public Article selectByUserId(Long userId) {
        Article article=articleMapper.selectByUserId(userId);
        return article;
    }

    @Override
    public Integer updateInfo(Long articleId,Long userId,Integer articleLike) {
        Integer rows=articleMapper.updateArticleLike(articleId,userId,articleLike);
        return rows;
    }

    /**
     * 某篇文章详情
     * @param articleDTO
     * @return
     */
    @Override
    public ArticleVO articleDetail(ArticleDTO articleDTO) {
        String key="articleDetail:"+articleDTO.getArticleId();
        //如果有，查缓存
        if (redisTemplate.hasKey(key)){
            ArticleVO articleVO= JSON.parseObject(redisTemplate.opsForHash().get(key,"articleInfo").toString(),ArticleVO.class);
            //增加文章浏览量
            if (redisTemplate.opsForHash().hasKey(key,"visit")){
                long views=redisTemplate.opsForHash().increment(key,"visit",1);
                articleVO.setArticleVisit((int)views);
            }else{
                redisTemplate.opsForHash().put(key,"visit",articleVO.getArticleVisit()+1);
                long views=redisTemplate.opsForHash().increment(key,"visit",1);
                articleVO.setArticleVisit(articleVO.getArticleVisit()+1);
            }
            articleVO.setArticleLike((Integer) redisTemplate.opsForHash().get(key,"like"));
            articleVO.setArticleCollection((Integer) redisTemplate.opsForHash().get(key,"collection"));
            articleVO.setArticleComment((Integer) redisTemplate.opsForHash().get(key,"comment"));
            articleVO.setArticleRetweetedarticleRetweeted((Integer) redisTemplate.opsForHash().get(key,"retweeted"));
            articleVO.setArticleVisit((Integer) redisTemplate.opsForHash().get(key,"visit"));
            saveBrowsing(articleDTO);
            return articleVO;
        }
        //获取文章信息
        ArticleVO articleVO=articleMapper.getArticleDetailByArticleId(articleDTO.getArticleId());
        //获取作者信息
        UserSimpleVO userSimpleVO=dubboUserDetail.selectUserCommentVOByUserId(articleVO.getUserId());
        //保存作者信息
        articleVO.setUserInfo(userSimpleVO);
        List<CommentVO> commentVOList=new ArrayList<>();
        //默认加载前三页 30行
        PageHelper.startPage(1,30);
        //依据类型获取评论列表
        //按点赞降序
        List<CommentVO> like=commentMapper.listByArticleIdLike(articleDTO.getArticleId());
        System.out.println("likesize"+like.size());
        PageHelper.startPage(1,30);
        //按时间降序
        List<CommentVO> time=commentMapper.listByArticleIdTime(articleDTO.getArticleId());
        System.out.println("timesize"+time.size());
        key="articleDetails:"+articleDTO.getArticleId();
        //缓存评论
        for (CommentVO commentVO:like) {
            //赞的排序set
            redisTemplate.opsForZSet().add(key+":commentLike",""+commentVO.getCommentId(),commentVO.getLikeNum());
            //将评论信息分为固定的和点赞数回复数，方便增改
            Map<String,Object> map=new HashMap<>();
            //获取评论人信息
            UserSimpleVO simpleVO=dubboUserDetail.selectUserCommentVOByUserId(commentVO.getCommenterId());
            commentVO.setNickname(simpleVO.getNickname());
            commentVO.setAvatar(simpleVO.getAvatar());
            map.put("commentInfo",JSON.toJSON(commentVO));
            map.put("likes",commentVO.getLikeNum());
            map.put("replys",commentVO.getReplayNum());
            redisTemplate.opsForHash().putAll(key+":commentDetail:"+commentVO.getCommentId(),map);
        }
        for (CommentVO commentVO:time) {
            //时间的排序set
            double commentTime= FormUtils.parseTimeByLocalDateTime(commentVO.getCommontTime());
            redisTemplate.opsForZSet().add(key+":commentTime",""+commentVO.getCommentId(),commentTime);
            //将评论信息分为固定的和点赞数回复数，方便增改
            Map<String,Object> map=new HashMap<>();
            //获取评论人信息
            UserSimpleVO simpleVO=dubboUserDetail.selectUserCommentVOByUserId(commentVO.getCommenterId());
            commentVO.setNickname(simpleVO.getNickname());
            commentVO.setAvatar(simpleVO.getAvatar());
            map.put("commentInfo",JSON.toJSON(commentVO));
            map.put("likes",commentVO.getLikeNum());
            map.put("replys",commentVO.getReplayNum());
            redisTemplate.opsForHash().putAll(key+":commentDetail:"+commentVO.getCommentId(),map);
        }
        //存完缓存后
        Set<String> list;
        if (COMMENT_TYPE.equals(articleDTO.getShowType())){
            //获取按赞排好序的
            list= redisTemplate.opsForZSet().reverseRange(key+":commentLike",0,29);
        }else{
            //获取按时间排好序的
            list = redisTemplate.opsForZSet().reverseRange(key+":commentTime",0,29);
        }
        for (String id:list){
            CommentVO commentVO=JSON.parseObject(redisTemplate.opsForHash().get(key+":commentDetail:"+id,"commentInfo").toString(),CommentVO.class);
            commentVO.setLikeNum((Integer) redisTemplate.opsForHash().get(key+":commentDetail:"+id,"likes"));
            commentVO.setReplayNum((Integer) redisTemplate.opsForHash().get(key+":commentDetail:"+id,"replys"));
            commentVOList.add(commentVO);
        }
        //保存comment列表
        articleVO.setCommentList(commentVOList);
        //缓存 3小时
//        redisTemplate.opsForValue().set(key, JSON.toJSON(articleVO),3,TimeUnit.HOURS);
        key="articleDetail:"+articleDTO.getArticleId();
        Map<String,Object> map=new HashMap<>();
        map.put("articleInfo",JSON.toJSON(articleVO));
        //点赞
        map.put("like",articleVO.getArticleLike());
        //评论
        map.put("comment",articleVO.getArticleComment());
        //浏览
        map.put("visit",articleVO.getArticleVisit());
        //收藏
        map.put("collection",articleVO.getArticleCollection());
        //转发
        map.put("retweeted",articleVO.getArticleRetweetedarticleRetweeted());
        redisTemplate.opsForHash().putAll(key,map);
        //增加文章浏览量
        if (redisTemplate.hasKey(key)){
            long views=redisTemplate.opsForHash().increment(key,"visit",1);
            articleVO.setArticleVisit((int)views);
        }else{
            redisTemplate.opsForValue().set(key+":viewNum",articleVO.getArticleVisit()+1);
            articleVO.setArticleVisit(articleVO.getArticleVisit()+1);
        }
        //缓存1小时
        redisTemplate.expire(key,1, TimeUnit.HOURS);
        saveBrowsing(articleDTO);
        return articleVO;
    }

    /**
     * 设置某一条文章的显示
     * @param id
     */
    @Override
    public void display(String id) {
        int rows=articleMapper.display(id);
        if (rows<1){
            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"设置失败，请稍后重试");
        }
    }
    /**
     * 设置某一条文章的隐藏
     * @param id
     */
    @Override
    public void hide(String id) {
        int rows=articleMapper.hide(id);
        if (rows<1){
            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"设置失败，请稍后重试");
        }
    }

    /**
     * 返回文章列表,按照时间展示最新
     * @param modelId
     * @return
     */
    @Override
    public List<SimpleArticleVO> getArticleList(Long modelId) {
        String key= RedisConstants.ARTICLE_LIST+"model"+modelId+":";
        //获取置顶
        List<SimpleArticleVO> tops=topService.getTopList(modelId);
        List<SimpleArticleVO> list=new ArrayList<>();
        list.addAll(tops);
        //检查缓存
        if (redisTemplate.hasKey(key)){
            //有缓存,获取27个结果的id
            Set<String> set=redisTemplate.opsForZSet().reverseRange(key+"time",0,29-list.size());
            for (String id:set) {
                SimpleArticleVO articleVO=JSON.parseObject(redisTemplate.opsForHash().get(key+"detail",id).toString(),SimpleArticleVO.class);
                list.add(articleVO);
            }
//            if (list.size()<30){
//                throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"系统繁忙");
//            }
            return list;
        }
        //没缓存
        //获取文章
        PageHelper.startPage(1,30);
        List<SimpleArticleVO> articles=articleMapper.getArticleList(modelId);
        if (articles==null ||articles.size()==0){
            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"系统繁忙");
        }
        Map<String,Object> map=new HashMap<>();
        //存入缓存
        for (SimpleArticleVO article:articles) {
            //获取文章信息
            if (article.getContent().length()>50){
                article.setContent(article.getContent().substring(0,50)+"...");
            }else{
                article.setContent(article.getContent());
            }
            double time= FormUtils.parseTimeByLocalDateTime(article.getCreateTime());
            //获取作者信息
            UserSimpleVO user=dubboUserDetail.selectUserCommentVOByUserId(article.getUserId());
            article.setNickName(user.getNickname());
            article.setAvatar(user.getAvatar());
            article.setIntroduction(user.getIntroduction());
            //把文章id作为value
            redisTemplate.opsForZSet().add(key+"time",""+article.getArticleId(),time);
            map.put(""+article.getArticleId(),JSON.toJSON(article));
        }
        redisTemplate.opsForHash().putAll(key+"detail",map);
        Set<String> set=redisTemplate.opsForZSet().reverseRange(key+"time",0,26);
        for (String id:set) {
            SimpleArticleVO articleVO=JSON.parseObject(redisTemplate.opsForHash().get(key+"detail",id).toString(),SimpleArticleVO.class);
            list.add(articleVO);
        }
//        if (list.size()<30){
//            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"系统繁忙");
//        }
        return list;
    }

    /**
     * 加载下一页文章列表
     * @param modelId
     * @param page 加载页数
     * @return
     */
    @Override
    public List<SimpleArticleVO> getArticleListNext(Long modelId,Integer page) {
        String key= RedisConstants.ARTICLE_LIST+"model"+modelId+":";
        List<SimpleArticleVO> list=new ArrayList<>();
        //检查缓存
        if (redisTemplate.hasKey(key+"time")){
            long total=27+page*10;
            //数量足够
            if(redisTemplate.opsForZSet().size(key+"time")>=total){
                //获取10个新数据返回
                Set<String> ids=redisTemplate.opsForZSet().reverseRange(key+"time",total-10,total-1);
                for (String id:ids) {
                    SimpleArticleVO articleVO=JSON.parseObject(redisTemplate.opsForHash().get(key+"detail",id).toString(),SimpleArticleVO.class);
                    list.add(articleVO);
                }
                System.out.println("list缓存够"+list);
                return list;
            }
            //数量不够，数据库获取30条
            PageHelper.startPage(page/2+2,30);
            List<SimpleArticleVO> articles=articleMapper.getArticleList(modelId);
            if (articles==null ||articles.size()==0){
                throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"系统繁忙");
            }
            Map<String,Object> map=new HashMap<>();
            //存入缓存
            for (SimpleArticleVO article:articles) {
                //获取文章信息
                if (article.getContent().length()>50){
                    article.setContent(article.getContent().substring(0,50)+"...");
                }else{
                    article.setContent(article.getContent());
                }
                double time= FormUtils.parseTimeByLocalDateTime(article.getCreateTime());
                //获取作者信息
                UserSimpleVO user=dubboUserDetail.selectUserCommentVOByUserId(article.getUserId());
                article.setNickName(user.getNickname());
                article.setAvatar(user.getAvatar());
                article.setIntroduction(user.getIntroduction());
                //把文章id作为value
                redisTemplate.opsForZSet().add(key+"time",""+article.getArticleId(),time);
                map.put(""+article.getArticleId(),JSON.toJSON(article));
            }
            redisTemplate.opsForHash().putAll(key+"detail",map);
            //获取缓存
            //获取10个新数据返回
            Set<String> ids=redisTemplate.opsForZSet().reverseRange(key+"time",total-10,total-1);
            for (String id:ids) {
                SimpleArticleVO articleVO=JSON.parseObject(redisTemplate.opsForHash().get(key+"detail",id).toString(),SimpleArticleVO.class);
                list.add(articleVO);
            }
            System.out.println("list缓存不够"+list);
            return list;
        }
        //没缓存
        //获取文章
        PageHelper.startPage(1,30+page*10);
        List<SimpleArticleVO> articles=articleMapper.getArticleList(modelId);
        if (articles==null ||articles.size()==0){
            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"系统繁忙");
        }
        Map<String,Object> map=new HashMap<>();
        //存入缓存
        for (SimpleArticleVO article:articles) {
            //获取文章信息
            if (article.getContent().length()>50){
                article.setContent(article.getContent().substring(0,50)+"...");
            }else{
                article.setContent(article.getContent());
            }
            double time= FormUtils.parseTimeByLocalDateTime(article.getCreateTime());
            //获取作者信息
            UserSimpleVO user=dubboUserDetail.selectUserCommentVOByUserId(article.getUserId());
            article.setNickName(user.getNickname());
            article.setAvatar(user.getAvatar());
            article.setIntroduction(user.getIntroduction());
            //把文章id作为value
            redisTemplate.opsForZSet().add(key+"time",""+article.getArticleId(),time);
            map.put(""+article.getArticleId(),JSON.toJSON(article));
        }
        redisTemplate.opsForHash().putAll(key+"detail",map);
//        if (list.size()<30){
//            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"系统繁忙");
//        }
        Set<String> ids=redisTemplate.opsForZSet().reverseRange(key+"time",0,30+page*10-1);
        for (String id:ids) {
            SimpleArticleVO articleVO=JSON.parseObject(redisTemplate.opsForHash().get(key+"detail",id).toString(),SimpleArticleVO.class);
            list.add(articleVO);
        }
        System.out.println("list没缓存"+list);
        return list;
    }

    /**
     * 查询用户个人发表的分享
     * @param userId
     * @param page
     * @return
     */
    @Override
    public JsonResult<List<SimpleArticleVO>> getUserArticleList(Long userId, Integer page) {
        //判断参数正确与否
        if (userId==null||page==null||page<1){
            throw new TimeyanServiceException(ResponseCode.ERR_NOTIME,"系统繁忙");
        }
        //查询该用户发表的分享信息
        //查询30个
        PageHelper.startPage(page,30);
        List<SimpleArticleVO> articles=articleMapper.getArticleListByUserId(userId);
        System.out.println("articles:"+articles);
        if (articles==null ||articles.size()==0){
            throw new TimeyanServiceException(ResponseCode.ERR_NOTIME,"系统繁忙");
        }
        return JsonResult.ok(articles);
    }

    @Override
    @Transactional
    public JsonResult<Void> addNewArticle(NewArticleDTO newArticleDTO) {
        if (newArticleDTO==null){
            throw new TimeyanServiceException(ResponseCode.ERR_BAD_REQUEST,"参数为空");
        }
        int line=articleMapper.addNewArticle(newArticleDTO);
        MultipartFile imgFile = newArticleDTO.getImgFile();
        if (imgFile!=null){
            Long articleId=articleMapper.getArticleIdByUserIdAndTitle(
                    newArticleDTO.getUserId(), newArticleDTO.getTitle());
        }
        if(line<1){
            throw new TimeyanServiceException(ResponseCode.ERR_INSERT,"发布分享失败");
        }
        return JsonResult.ok();
    }

    @Override
    public Long getUserIdByArticleId(Long articleId) {
        return articleMapper.getUserIdByArticleId(articleId);
    }

    @Override
    public Article getAricleByAricleId(Long articleId){
        return articleMapper.getArticleSimpleByArticleId(articleId);
    }
    //保存浏览记录
    private void saveBrowsing(ArticleDTO articleDTO){
        BrowsingHistory history=new BrowsingHistory();
        history.setUserId(articleDTO.getUserId());
        history.setModuleId(articleDTO.getModelId());
        history.setSourceId(articleDTO.getArticleId());
        history.setModuleType("0");
        history.setViewTime(LocalDateTime.now());
        dubboBrowsingHistory.addBrowsingHistory(history);
    }
}
